package org.linlinjava.litemall.wx.web;

import com.github.pagehelper.PageInfo;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.linlinjava.litemall.core.util.ResponseUtil;
import org.linlinjava.litemall.core.validator.Order;
import org.linlinjava.litemall.core.validator.Sort;
import org.linlinjava.litemall.db.domain.*;
import org.linlinjava.litemall.db.service.*;
import org.linlinjava.litemall.db.util.DateUtil;
import org.linlinjava.litemall.wx.annotation.LoginUser;
import org.linlinjava.litemall.wx.util.CloneUtil;
import org.linlinjava.litemall.wx.vo.GoodsDetailVo;
import org.linlinjava.litemall.wx.vo.GoodsListVo;
import org.linlinjava.litemall.wx.vo.RecommendVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import javax.validation.constraints.NotNull;
import java.util.*;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * 商品服务
 */
@RestController
@RequestMapping("/wx/goods")
@Validated
@RequiredArgsConstructor(onConstructor = @_(@Autowired))
@Api("商品服务")
public class WxGoodsController {
	private final Log logger = LogFactory.getLog(WxGoodsController.class);

	private final GoodsService goodsService;

	private final FootprintService footprintService;

	private final OrderGoodsService orderGoodsService;

	private final CategoryService categoryService;

	private final SearchHistoryService searchHistoryService;

	private final static ArrayBlockingQueue<Runnable> WORK_QUEUE = new ArrayBlockingQueue<>(9);

	private final static RejectedExecutionHandler HANDLER = new ThreadPoolExecutor.CallerRunsPolicy();

	private static final ThreadPoolExecutor executorService = new ThreadPoolExecutor(16, 16, 1000, TimeUnit.MILLISECONDS, WORK_QUEUE, HANDLER);

	/**
	 * 商品详情
	 * <p>
	 * 用户可以不登录。
	 * 如果用户登录，则记录用户足迹以及返回用户收藏信息。
	 *
	 * @param userId 用户ID
	 * @param id     商品ID
	 * @return 商品详情
	 */
	@GetMapping("detail")
	@ApiOperation("商品详情")
	public Object detail(@LoginUser Integer userId, @NotNull Integer id) {
		LitemallGoods good = goodsService.findById(id);
		GoodsDetailVo goodsDetailVo = CloneUtil.clone(good, GoodsDetailVo.class);
		goodsDetailVo.setPrice(good.getRetailPrice());
		goodsDetailVo.setSaleNum(orderGoodsService.goodsCount(id));
		goodsDetailVo.setCategoryName(categoryService.findById(good.getCategoryId()).getName());
		// 秒杀信息
		if (!StringUtils.isEmpty(good.getStartTime())) {
			if (DateUtil.isBetween(good.getStartTime(), good.getEndTime())) {
				goodsDetailVo.setIsKill(true);
				goodsDetailVo.setStartTime(good.getStartTime());
				goodsDetailVo.setEndTime(good.getEndTime());
				goodsDetailVo.setKillPrice(good.getKillPrice());
			}
		}

		// 记录用户的足迹 异步处理
		if (userId != null) {
			executorService.execute(()->{
				LitemallFootprint footprint = new LitemallFootprint();
				footprint.setUserId(userId);
				footprint.setGoodsId(id);
				footprint.setCategoryId(good.getCategoryId());
				footprintService.add(footprint);
			});
		}
		if (!StringUtils.isEmpty(goodsDetailVo.getRecommend())) {
			goodsDetailVo.setRecommendVos(recommend(goodsDetailVo.getRecommend()));
		}

		return ResponseUtil.ok(goodsDetailVo);
	}

	private List<RecommendVo> recommend(String[] recommend) {
		List<String> collect = Arrays.stream(recommend).collect(Collectors.toList());
		List<RecommendVo> recommendVoList = new ArrayList<>();
		collect.forEach(str ->{
			RecommendVo recommendVo = new RecommendVo();
			int goodId = Integer.parseInt(str);
			LitemallGoods good = goodsService.findById(goodId);
			recommendVo.setGoodId(goodId);
			recommendVo.setName(good.getName());
			recommendVo.setPicUrl(good.getPicUrl());
			recommendVo.setPrice(good.getRetailPrice());
			recommendVo.setCategoryName(categoryService.findById(good.getCategoryId()).getName());
			recommendVoList.add(recommendVo);
		});
		return recommendVoList;
	}

	/**
	 * 商品分类类目
	 *
	 * @param id 分类类目ID
	 * @return 商品分类类目
	 */
	@GetMapping("category")
	@ApiOperation("商品分类类目")
	public Object category(@NotNull Integer id) {
		LitemallCategory cur = categoryService.findById(id);
		LitemallCategory parent;
		List<LitemallCategory> children;

		if (cur.getPid() == 0) {
			parent = cur;
			children = categoryService.queryByPid(cur.getId());
			cur = children.size() > 0 ? children.get(0) : cur;
		} else {
			parent = categoryService.findById(cur.getPid());
			children = categoryService.queryByPid(cur.getPid());
		}
		Map<String, Object> data = new HashMap<>();
		data.put("currentCategory", cur);
		data.put("parentCategory", parent);
		data.put("brotherCategory", children);
		return ResponseUtil.ok(data);
	}

	/**
	 * 根据条件搜素商品
	 * <p>
	 * 1. 这里的前五个参数都是可选的，甚至都是空
	 * 2. 用户是可选登录，如果登录，则记录用户的搜索关键字
	 *
	 * @param categoryId 分类类目ID，可选
	 * @param keyword    关键字，可选
	 * @param userId     用户ID
	 * @param page       分页页数
	 * @param limit       分页大小
	 * @param sort       排序方式，支持"add_time", "retail_price"或"name"
	 * @param order      排序类型，顺序或者降序
	 * @return 根据条件搜素的商品详情
	 */
	@GetMapping("list")
	@ApiOperation("根据条件搜索商品")
	public Object list(
		Integer categoryId,
		String keyword,
		@LoginUser Integer userId,
		@RequestParam(defaultValue = "1") Integer page,
		@RequestParam(defaultValue = "10") Integer limit,
		@Sort(accepts = {"add_time", "retail_price", "name"}) @RequestParam(defaultValue = "add_time") String sort,
		@Order @RequestParam(defaultValue = "desc") String order) {

		//添加到搜索历史
		if (userId != null && !StringUtils.isEmpty(keyword)) {
			LitemallSearchHistory searchHistoryVo = new LitemallSearchHistory();
			searchHistoryVo.setKeyword(keyword);
			searchHistoryVo.setUserId(userId);
			searchHistoryVo.setFrom("wx");
			searchHistoryService.save(searchHistoryVo);
		}

		//查询列表数据
		List<LitemallGoods> goodsList = goodsService.querySelective(userId, categoryId, keyword, page, limit, sort, order);

		List<GoodsListVo> goodsListVos = CloneUtil.cloneList(goodsList, GoodsListVo.class);

		goodsListVos.forEach(good->{
			if (!StringUtils.isEmpty(good.getStartTime())) {
				if (DateUtil.isBetween(good.getStartTime(), good.getEndTime())) {
					good.setIsKill(true);
				}
			}
			good.setCategoryName(categoryService.findById(good.getCategoryId()).getName());
		});

		PageInfo<GoodsListVo> pagedList = PageInfo.of(goodsListVos);

		Map<String, Object> entity = new HashMap<>();
		entity.put("list", goodsListVos);
		entity.put("total", pagedList.getTotal());
		entity.put("page", pagedList.getPageNum());
		entity.put("limit", pagedList.getPageSize());
		entity.put("pages", pagedList.getPages());

		// 因为这里需要返回额外的filterCategoryList参数，因此不能方便使用ResponseUtil.okList
		return ResponseUtil.ok(entity);
	}

	/**
	 * 商品详情页面“大家都在看”推荐商品
	 *
	 * @param id, 商品ID
	 * @return 商品详情页面推荐商品
	 */
	@GetMapping("related")
	@ApiOperation("商品详情页面“大家都在看”推荐商品")
	public Object related(@NotNull Integer id) {
		LitemallGoods goods = goodsService.findById(id);
		if (goods == null) {
			return ResponseUtil.badArgumentValue();
		}

		// 目前的商品推荐算法仅仅是推荐同类目的其他商品
		int cid = goods.getCategoryId();

		// 查找六个相关商品
		int related = 6;
		List<LitemallGoods> goodsList = goodsService.queryByCategory(cid, 0, related);
		return ResponseUtil.okList(goodsList);
	}

	/**
	 * 在售的商品总数
	 *
	 * @return 在售的商品总数
	 */
	@GetMapping("count")
	@ApiOperation("在售的商品总数")
	public Object count() {
		Integer goodsCount = goodsService.queryOnSale();
		return ResponseUtil.ok(goodsCount);
	}

}